package com.ms.game.bank.db;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;

import com.ms.game.bank.CashChangeWay;
import com.ms.game.bank.VipChangeWay;
import com.ms.game.bank.container.BankInfoBin;
import com.ms.game.bank.message.BankResponse;
import com.ms.game.common.container.LevelInfoBin;
import com.ms.game.common.container.LevelInfoBinUtil;
import com.ms.game.common.container.LevelUpInfo;
import com.ms.player.Player;
import com.ms.player.PlayerAttributeType;
import com.ms.player.PlayerUserType;
import com.ms.player.UpdateAttributeList;
import com.ms.service.error.ErrorCode;
import com.ms.service.module.analysisgroup.AnalysisGroupProcessor;
import com.ms.service.module.analysisgroup.CoinExpenditureWay;
import com.ms.service.module.datacenterlite.CentralAsyncCommand;
import com.ms.service.module.zone.BasicZone;
import com.ms.service.module.zone.module.BasicZoneModule;
import com.xpec.c4.db.dao.PlayerDAO;
import com.xpec.c4.db.dao.PlayerLevelCalculator;
import com.xpec.c4.db.hibernate.manager.HibernateLogManager;
import com.xpec.c4.db.model.PlayerModel;
import com.xpec.c4.game.common.Helper;
import com.xpec.c4.game.datamanager.agent.money.ChangeCoinLister;
import com.xpec.c4.game.datamanager.agent.money.CoinType;
import com.xpec.c4.game.datamanager.agent.money.MoneyChangeParam;
import com.xpec.c4.game.datamanager.agent.money.MoneyChangeWay;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GUIDFactory;
import com.xpec.c4.game.utility.GUIDType;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.message.MessageAction;

public class UpdateAcoountCashPlayerVipDCLAsync extends CentralAsyncCommand {

	private static final long serialVersionUID = -1315141151198523013L;
	
	private static final Log log = LogFactory.getLog(UpdateAcoountCashPlayerVipDCLAsync.class);
	
	/**
	 * 轉換的點數
	 */
	public long cashPoint;
	
	public GUID playerID;
	
	public String playerName;
	
	public GUID accountID;
	
	public GUID sessionID;
	
	public int userType;
	
	public boolean isFirstChange;
	
	private boolean isCashLoad = true;
	
	private boolean isSave = true;
	
	/**
	 * account轉換後的值
	 */
	private long afterAccountCash;
	
	/**
	 * 帳號點數是否足夠
	 */
	private boolean isEnough = false;
	
	/**
	 * vip等級
	 */
	private int afterVip;
	
	/**
	 * 改變後vip經驗值
	 */
	private long afterVipExp;
	
	/**
	 * 改變前vip等級
	 */
	private int beforeVipLv;
	
	/**
	 * 改變後的角色等級
	 */
	private int beforeLv;
	
	/**
	 * 改變後的角色等級
	 */
	private int afterLv;
	
	/**
	 * 改變後的角色等級
	 */
	private BigDecimal afterExp;
	
	/**
	 * 改變的金幣值
	 */
	private BigDecimal goldChangeValueForAnalysis;

	@Override
	public void asyncExecute() throws Exception {
		String orderId = GUIDFactory.createUUID(GUIDType.TYPE_CASH_POINT).toString();
		UpdateAttributeList updateAttributeList = new UpdateAttributeList();
		PlayerModel model= PlayerDAO.loadPlayerModelByGuid(playerID);		
		// TODO kevin loadAccountCash [v] 點數轉金錢
		Object[] cashOb = BankDAO.loadAccountCashPoint(accountID);
		
		if (cashOb == null) {
			isCashLoad = false;
			return;
		}
		
		long beforeAccountCash = (long)cashOb[0];
		if(isFirstChange){
			isFirstChange = !(boolean)cashOb[1];
		}
		afterAccountCash =  beforeAccountCash - cashPoint;
		if(afterAccountCash < 0){
			isEnough = false;
			return;
		}
		
		isEnough = true;
		
		// account扣點
		GameUtility.writeCashUpdateConsoleLog("UpdateAcoountCashPlayerVipDCLAsync.asyncExecute()", accountID.toString(), beforeAccountCash, cashPoint, afterAccountCash);
		isSave = BankDAO.UpdateAccountCashPoint(accountID, afterAccountCash, isFirstChange);
		if (!isSave) {
			GameUtility.writeCashUpdateConsoleLog("UpdateAcoountCashPlayerVipDCLAsync.asyncExecute() DB Operation Fail", accountID.toString(), beforeAccountCash, cashPoint, afterAccountCash);
			return;
		}
			

		// player gold 兌換變化
		BigDecimal beforePlayerGold = model.getGoldCoin();
		BigDecimal goldChangeValue = new BigDecimal(cashPoint * BankInfoBin.getInstance().getPointToGoldRatio());
		BigDecimal afterPlayerGold = beforePlayerGold.add(goldChangeValue);

		//如果是小樂 change way 跟一般玩家不一樣
		CashChangeWay changeWay = (userType == PlayerUserType.ROBORT)?CashChangeWay.SUB_ROBOT_CHANGE_POINT_TO_GOLD:CashChangeWay.SUB_CHANGE_POINT_TO_GOLD;
		
		// account扣點後的log 直接寫入log
		Session sessionlog = HibernateLogManager.txBegin();
		CashLogModel logModel = new CashLogModel();
		logModel.setOrderId(orderId);
		logModel.setAccountId(accountID.toString());
		logModel.setPlayerId(playerID.toString());
		logModel.setPlayerName(playerName);
		logModel.setCashBeforeChange(beforeAccountCash);
		logModel.setCashChangeValue(cashPoint);
		logModel.setCashAfterChange(afterAccountCash);
		logModel.setGoldBeforeChange(beforePlayerGold);
		logModel.setGoldChangeValue(goldChangeValue);
		logModel.setGoldAfterChange(afterPlayerGold);
		logModel.setChangeWay(changeWay.getId());
		logModel.setChangeWayDesc(changeWay.getDesc());
		sessionlog.save(logModel);
		HibernateLogManager.txCommitFailRollbackClearSession();
		
		//player VIP經驗值
		ArrayList<LevelUpInfo> levelInfo = LevelInfoBin.getInstance().getVipLevelUpInfoList();
		//改變前
		beforeVipLv = model.getVip();
		long beforeVipExp = model.getVipExp();
		
		if(beforeVipLv < levelInfo.size()){
			//Vip未滿才檢查
			model.setVipExp(model.getVipExp() + cashPoint);
			for(int index = 0 ; index < levelInfo.size() ; index ++){
				LevelUpInfo info = levelInfo.get(index);
				if(info.getNeedExp() > model.getVipExp()){
					model.setVip(info.getLevel() - 1);
					break;
				}
				//最高等級vip
				if(info.getLevel() == levelInfo.size() -1){
					model.setVip(info.getLevel());
				}
			}
			
			VipLogModel vipLogModel = new VipLogModel();
			vipLogModel.setOrderId(orderId);
			vipLogModel.setAccountId(accountID.toString());
			vipLogModel.setPlayerId(playerID.toString());
			vipLogModel.setPlayerName(playerName);
			vipLogModel.setUserType(model.getUserType());
			vipLogModel.setVipBefore(beforeVipLv);
			vipLogModel.setVipAfter(model.getVip());
			vipLogModel.setExpBeforeChange(beforeVipExp);
			vipLogModel.setExpChangeValue(cashPoint);
			vipLogModel.setExpAfterChange(model.getVipExp());
			vipLogModel.setChangeWay(VipChangeWay.ADD_CHANGE_POINT_TO_GOLD.getId());
			vipLogModel.setChangeWayDesc(VipChangeWay.ADD_CHANGE_POINT_TO_GOLD.getDesc());
			getCurrentModuleServer().saveDbLog(vipLogModel);
		}
		afterVip = model.getVip();
		afterVipExp = model.getVipExp();
		
		beforeLv = model.getLevel();
		//第一次轉點的時候，要把角色等級也升到一
		if(beforeVipLv == 0 && afterVip > 0 && beforeLv == 0){
		 	afterLv = 1;
		 	model.setExp(LevelInfoBinUtil.getExpByLevel(beforeLv, (afterLv - beforeLv)));
		 	afterExp = model.getExp();
			updateAttributeList.addUpdateValue(PlayerAttributeType.LEVEL, afterLv);
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP, afterExp);
			
			HashMap<String, Long> expInfos = LevelInfoBinUtil.getExpInfos(afterExp);
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_IN_CURRENT_LEVEL, expInfos.get(PlayerLevelCalculator.EXP_IN_CURRENT_LEVEL));
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_TO_NEXT_LEVEL, expInfos.get(PlayerLevelCalculator.EXP_TO_NEXT_LEVEL));
		}
		
		
		if(isSave){
			updateAttributeList.addUpdateValue(PlayerAttributeType.VIP, afterVip);
			updateAttributeList.addUpdateValue(PlayerAttributeType.VIP_EXP, afterVipExp);

			if (isFirstChange)
				updateAttributeList.addUpdateValue(PlayerAttributeType.STORE_REWARD_CONTINUOUS_LOGIN_COUNT, 1);

			//更新玩家vip經驗和等級
//			isSave = BankDAO.UpdatePlayerVip(playerID, afterVip, afterVipExp,isFirstChange);
			
			PlayerDAO.updatePlayerFromAttrList(playerID.toString(), updateAttributeList.getUpdateList(), userType);
			
			goldChangeValueForAnalysis = goldChangeValue;
		}
	}

	/**
	 * callback
	 * @see com.ms.game.bank.BankProcessor#changePointToGoldCoinCallback
	 */
	@Override
	public void callBackExecute(Object... userData) throws Exception {
		if(log.isInfoEnabled()){
			log.info(GameUtility.getCurMethodName() + " Start! " + "playerId = " + playerID.toString() + " Name = " + playerName);
		}
		BankResponse response = new BankResponse();
		BasicZoneModule module = (BasicZoneModule)userData[0];
		BasicZone zone = module.getZone();

		if(!isCashLoad){
			//load cash point 失敗
			response.errorCode = ErrorCode.DB_OPERATION_FAIL;
			zone.changePointToGoldCallback(sessionID , response , playerID);
			return;
		}

		if(!isEnough){
			//帳號點數不足
			response.errorCode = ErrorCode.CASH_POINT_NOT_ENOUGH;
			zone.changePointToGoldCallback(sessionID , response , playerID);
			return;
		}
		
		if(!isSave){
			//存失敗
			response.errorCode = ErrorCode.DB_OPERATION_FAIL;
			zone.changePointToGoldCallback(sessionID , response , playerID);
			return;
		}

		//更新zone上的資料
		Player playerData = module.getZone().getPlayer(playerID);
		
		if(playerData != null){
			playerData.setVip(afterVip);
			playerData.setVipExp(afterVipExp);
			if(beforeVipLv == 0 && afterVip > 0 && beforeLv == 0){
				playerData.setLevel(afterLv);
				playerData.setExp(afterExp);
			}
			
			if(isFirstChange){
				playerData.setHaveFirstStoreCharacter(true);
				playerData.setStoreRewardContinuousLoginCount(1);
			}
		}

		
		//點數轉金錢
		BigDecimal totalGold = Helper.mul(cashPoint, BankInfoBin.getInstance().getPointToGoldRatio());
		
		ChangeCoinLister coinLister = new ChangeCoinLister();
		coinLister.addCoin(CoinType.GOLD, totalGold);
		
		if(log.isInfoEnabled()){
			log.info(GameUtility.getCurMethodName() + " updatePlayerMoneyToDC! " + "playerId = " + playerID.toString() + " Name = " + playerName);
		}
		
		//金錢寫回DC，給自己
		module.getPlayerDataAgent().updatePlayerMoneyToDC(GUIDFactory.createUUID(GUIDType.TYPE_BANK_MONEY),
				playerData, coinLister, MoneyChangeWay.ADD_BANK_CHANGE_POINT_TO_GOLD, MoneyChangeParam.NO_JACKPOT,
				false, null, null, module, null, null, null, null, null, module.getBank(),
				"changePointToGoldCoinCallback", sessionID, MessageTypes.S_BANK_CHANGE_POINT_TO_GOLD_RESPONSE,
				module, afterAccountCash);
	
		if (isFirstChange && !playerData.isRobot()) { 
			MessageAction.sendMessage(sessionID, MessageTypes.S_FIRST_STORE_NOTIFY, "");
		}

		if(!playerData.isRobot()){
			//送到統計C幣支出
			AnalysisGroupProcessor.sendCoinExpenditureToAnalysis(CoinExpenditureWay.POINT_EXCHANGE, goldChangeValueForAnalysis);
		}
	}
}
